热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

主存|篇文章_存储优化查询分离

篇首语:本文由编程笔记#小编为大家整理,主要介绍了存储优化--查询分离相关的知识,希望对你有一定的参考价值。 上一篇文章中我们讲解了利用数据库分区与冷热分离的方式来优化

篇首语:本文由编程笔记#小编为大家整理,主要介绍了存储优化--查询分离相关的知识,希望对你有一定的参考价值。



上一篇文章中我们讲解了利用数据库分区与冷热分离的方式来优化存储,虽然解决了查询速度慢的问题,但是在海量数据情况下依然会出现查询缓慢问题,并且部分系统中的冷热数据也是需要频繁或同时查询的。那么,这篇文章中我将带领大家来学习一下如何在设计系统架构时解决海量的数据存储与查询。


一、案例

我们有一个自动化舆情系统,简要的工作流程是这样的:每天数据采集服务会从公共社交媒体上采集数据并存入数据库,识别服务读取数据库中存储的数据按照一定的规则进行分析识别,并将分析识别的结果存入库中,客户端实时读取数据库的分析识别结果,将信息展示出来,而且该系统还要支持舆情追溯功能(例如某人在某公共社交平台发布了不良言论,可以通过该系统查找他以前发布的所有言论以及所有言论的识别结果)。
根据上面对舆情系统的简要描述我们可知,该系统需要采集大量的数据来进行分析,并且需要对历史数据进行查询。因此该系统具备如下两个特征:



  1. 海量数据;

  2. 冷热数据同时查询。

那么根据这两个特征,我们就不能使用上一篇文章中所说的分区或冷热分离的方式来设计数据存储架构了。就目前来看比较适合的就是查询分离方案(目前指的是在这篇文章中,下一篇文章针对舆情系统还有更好的数据存储解决方案)。


二、简介


2.1 概念

每次向数据库中更新数据的同时,将数据也保存到其他存储系统中(其他存储系统可以是),当用户查询数据的时候直接从其他从出系统中查询出即可。这个更新的数据库被称为主存储,用来查询的数据库被称为查询存储。基本架构图如下:


2.2 适用场景

一般来说如果遇到如下问题就可以使用查询分离:



  1. 数据量大,单表数据达到千万;

  2. 查询速度慢,即使加了索引也是很慢;

  3. 存在复杂的表关联查询;

  4. 所有数据都有可能被修改和查询。


三、实现

查询分离的实现思一般分三个步骤:



  1. 如何触发;

  2. 如何实现

  3. 查询存储如何存储。

下面我们就来一一讲解一下。


3.1 如何触发

常见的查询分离触发方式有三种:



  1. 在向主存储更新数据后马上向查询存储更新同样的数据,并在查询存储数据更新完成后向用户返回结果。这种触发方式虽然保证了查询存储数据的实时性和一致性,并且业务逻辑也可控,但是对代码的侵入较大,只要是涉及更新主存储的代码,都要加入向查询存储更新数据的代码。而且这种方式还会减缓写操作的响应时间,因为我们要等待查询存储的数据跟新完成后才能返回响应结果。

  2. 在向主存储更新数据后异步更新查询存储,不等待查询存储数据更新完成,就向用户返回结果。这种方式不影响主流程,但是如果在查询存储更新前,用户进行了相关查询,就会返回过时的数据,而且这种方式对代码同样有侵入性。

  3. 监控主存储日志,如果发生变更,就去更新查询存储。这种方式不影响主流程,对业务代码零侵入,但是在查询存储更新前,用户可能会查到过时的数据,并且这种方式的架构比前两种方式复杂。

下表列出了这三种方式适合的场景:























触发方式适合场景
方式一业务代码简单,而且对写操作响应速度要求不高
方式二业务代码相对复杂,对写操作响应速度有要求
方式三业务代码很复杂,并且代码改动成本高

针对上面三种触发方式的简单讲解和适合场景的描述可知,我们的舆情系统适用于方式二。


3.2 如何实现

我们已经在上一小节中确定使用第二种触发方式来设计我们的数据存储架构了。实现它的思路可以简述为:单独启动一个线程来对查询存储进行更新。但是,这种方式在实现时要考虑如下三个情况:



  1. 当出现大量写入操作时,更新查询存储的线程会很多,就会给舆情系统、查询存储、甚至服务器带来巨大的压力,那么这个时候我们就需要控制跟新查询存储的线程数量了;

  2. 如果在更新查询存储的过程中出现了更新失败的情况,我们应该引入重试机制,那么我们该怎么标识需要重试的数据;

  3. 多线程并发更新查询存储时该怎么处理?

针对上述三种情况,我们可以使用 MQ来解决,思路也很简单:当向主存储更新数据时,都要向MQ发出一个通知,MQ在收到通知后启动一个线程来更新查询存储。
当然在使用 MQ 的时候也会遇到各种问题,最常见的问题就是 MQ 挂掉了。当 MQ 挂掉后会出现如下两种情况:



  1. 主存储跟新完后向MQ发送通知,但是MQ无法收到这个通知,因此数据也就不会更新到查询库里,那么就出现了数据丢失的问题;

  2. MQ 消费者收到消息去更新查询存储后,告诉MQ消费完成,但是MQ这时挂了,已经收不到这个反馈了,但是在MQ重新启动后,这条消息又被投递了,这时就出现了重复投递的问题。

前述的这两种情况我们可以在主存储中增加一个 需要更新到查询存储 字段,每次在向主存储更新数据时就将这个字段设置为 true,扎样在向MQ发消息时只用发送一个简单的更新消息即可,不需要向MQ发送包含数据ID的消息。查询存储更新服务在获取到这个消息后,首先在主存储中查询 ***需要更新到查询存储***字段为true的数据,然后将这些数据批量更新到查询存储中,更新完毕后再将这些数据的**需要更新到查询存储字段改为false即可。
我们也可以利用MQ来实现
削峰
,当更新的请求太多时通过MQ来控制执行同步查询库的线程数。
数据更新到查询存储失败问题我们可以引入重试机制,并且只有在更新成功后才去修改***需要更新到查询存储***字段的值。当然,并不是每次重试机制都能将数据更新成功,因此我们可以设定一个重试次数阈值,当数据重试次数达到这个阈值时就需要及时通知相关人员进行人工干预了。

关于并发问题的解决方法可以参考上一篇文章。
这一小节还剩最后一个问题,时序性问题。例如小明先将A数据更新为123,小红后将A数据更新为321,但是更新查询存储时,小红的更新线程却先于小明的更新线程启动,这时就出现了小明的旧数据覆盖了小红的新数据。解决这个问题也很简单,在主存储中增加 最后更新时间 字段,线程更新完查询存储后,检查当前数据的***最后更新时间*** 字段的值是否和线程刚启动时是一样的,并且***需要更新到查询存储***字段为false,如果满足条件就将***需要更新到查询存储***字段改成true,在做一次更新查询存储活动。


3.3 查询存储如何存储

一般来说比较常见的存储方案是使用 Elasticsearch、MongoDB或Redis,这三种方案都时候复杂查询。但是,具体存储方案的选型应该根据开发组技术情况和项目情况来走。


四、总结

这一篇文章主要讲了查询分离的知识以及如何设计数据存储架构,下一篇我将优化本篇案例的解决方案。


推荐阅读
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • FinOps 与 Serverless 的结合:破解云成本难题
    本文探讨了如何通过 FinOps 实践优化 Serverless 应用的成本管理,提出了首个 Serverless 函数总成本估计模型,并分享了多种有效的成本优化策略。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入理解 SQL 视图、存储过程与事务
    本文详细介绍了SQL中的视图、存储过程和事务的概念及应用。视图为用户提供了一种灵活的数据查询方式,存储过程则封装了复杂的SQL逻辑,而事务确保了数据库操作的完整性和一致性。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • MySQL缓存机制深度解析
    本文详细探讨了MySQL的缓存机制,包括主从复制、读写分离以及缓存同步策略等内容。通过理解这些概念和技术,读者可以更好地优化数据库性能。 ... [详细]
  • Hadoop入门与核心组件详解
    本文详细介绍了Hadoop的基础知识及其核心组件,包括HDFS、MapReduce和YARN。通过本文,读者可以全面了解Hadoop的生态系统及应用场景。 ... [详细]
  • 深入解析:阿里实战 SpringCloud 微服务架构与应用
    本文将详细介绍 SpringCloud 在微服务架构中的应用,涵盖入门、实战和案例分析。通过丰富的代码示例和实际项目经验,帮助读者全面掌握 SpringCloud 的核心技术和最佳实践。 ... [详细]
  • 本文探讨了领域驱动设计(DDD)的核心概念、应用场景及其实现方式,详细介绍了其在企业级软件开发中的优势和挑战。通过对比事务脚本与领域模型,展示了DDD如何提升系统的可维护性和扩展性。 ... [详细]
  • 微软Exchange服务器遭遇2022年版“千年虫”漏洞
    微软Exchange服务器在新年伊始遭遇了一个类似于‘千年虫’的日期处理漏洞,导致邮件传输受阻。该问题主要影响配置了FIP-FS恶意软件引擎的Exchange 2016和2019版本。 ... [详细]
  • 通过Web界面管理Linux日志的解决方案
    本指南介绍了一种利用rsyslog、MariaDB和LogAnalyzer搭建集中式日志管理平台的方法,使用户可以通过Web界面查看和分析Linux系统的日志记录。此方案不仅适用于服务器环境,还提供了详细的步骤来确保系统的稳定性和安全性。 ... [详细]
author-avatar
手机用户2502875921
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有